package cn.good.yan.service.t2;

import com.google.common.primitives.Ints;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 2 演示 - Redis - 抢红包
 *
 * @author shengren.yan
 * @create 2023-11-08
 */
@Service
@Slf4j
public class RedService {

    @Autowired
    private RedisTemplate redisTemplate;

    // 存的红包的key - redis的结构是list  结构：红包：20,30,10 （总共3个包，分别多少钱存在该key中）
    public static final String RED_PACKAGE_KEY = "redpackage:";

    // 抢的红包的key   - redis的结构是hash  结构：map  红包key-用户id1，红包key-用户id2，红包key-用户id2
    public static final String RED_PACKAGE_CONSUME_KEY = "redpackage:consume";

    /**
     * 拆红包的算法 --->  二倍均值算法
     *
     * @param totalMoney       金额
     * @param redpackageNumber 红包个数
     * @return
     */
    public Integer[] splitRedPackageAlgorithm(int totalMoney, int redpackageNumber) {
        Integer[] redPackageNums = new Integer[redpackageNumber];
        // 已经被抢夺的红包金额
        int useMoney = 0;
        for (int i = 0; i < redpackageNumber; i++) {
            if (i == redpackageNumber - 1) {
                redPackageNums[i] = totalMoney - useMoney;
            } else {
                // 二倍均值算法，每次拆分后塞进子红包的金额
                // 金额 = 随机取件（0，（剩余红包金额 / 未被抢的剩余红包数 N ）* 2 ）
                int avgMoney = ((totalMoney - useMoney) / (redpackageNumber - i)) * 2;
                redPackageNums[i] = 1 + new Random().nextInt(avgMoney - 1);
            }
            useMoney = useMoney + redPackageNums[i];
        }
        return redPackageNums;
    }

    /**
     * 发红包
     *
     * @param totalMoney        金额
     * @param num  红包个数
     */
    public String sendRedPackage(int totalMoney, int num) {
        // 1. 拆红包，将总金额totalMoney拆分成 num 个子红包
        // 拆分红包算法（二倍均值算法）通过后获得的多个子红包数组 （得到该红包的集合 如：30,12,20）
        Integer[] splitRedPackages = splitRedPackageAlgorithm(totalMoney, num);

        // 2. 发红包并保存进 list 结构 并且设置过期时间
        String key = RED_PACKAGE_KEY + UUID.randomUUID().toString();
        // 将 红包的集合，存入redis中（从左插入）
        redisTemplate.opsForList().leftPushAll(key, splitRedPackages);
        // 将key设置过期时间，为1天
        redisTemplate.expire(key, 1, TimeUnit.DAYS);

        // 3.发红包ok，返回前台显示
//        int[] array = Arrays.stream(splitRedPackages).mapToInt(Integer::valueOf).toArray();
//        List<Integer> list = Ints.asList(splitRedPackages);
        return key + "\t" + Ints.asList(Arrays.stream(splitRedPackages).mapToInt(Integer::valueOf).toArray());
    }

    /**
     * 抢红包
     * @param redPackageKey  红包的key
     * @param userId         用户id
     * @return {@link String}
     */
    public String robRedPackage(String redPackageKey, String userId) {
        // 1.验证某个用户是否抢过红包，不可以多抢（key是 红包id-用户id）
        Object redPackage = redisTemplate.opsForHash().get(RED_PACKAGE_CONSUME_KEY + redPackageKey, userId);
        // 2.没有抢过红包可以抢，如果抢过返回 -2 表示抢过
        if (null == redPackage) {
            // 2.1 从 list 结构中出队一个作为抢的红包，开始抢红包，将红包的list，左出一个值
            Object partRedPackage = redisTemplate.opsForList().leftPop(RED_PACKAGE_KEY + redPackageKey);
            if (partRedPackage != null) {
                // 2.2 抢到红包后 需要记录到hash结构中 记录每人抢到的红包，把记录存在 hash的Redis对象中
                redisTemplate.opsForHash().put(RED_PACKAGE_CONSUME_KEY + redPackageKey, userId, partRedPackage);
                System.out.println("用户" + userId + "\t 抢到了多少钱的红包：" + partRedPackage);
                // TODO  后续异步进mysql或者MQ进一步做统计处理，每一年你发出多少红包，抢到了多少红包
                return String.valueOf(partRedPackage);
            }
            // 2. 抢完了
            return "errorCode: -1, 红包抢完了";
        } else {
            // 3. 抢过了红包
            int myRedPackage = (int) redisTemplate.opsForHash().get(RED_PACKAGE_CONSUME_KEY + redPackageKey, userId);
            return "errorCode: -2,  message:" + userId + "\t  你已经抢过了红包，不能在抢了,你抢的金额是" + myRedPackage;
        }

    }

}
